#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
#include <QTextEdit>
#include <QFile>
#include <QKeySequence>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <QHeaderView>
#include <QFileDialog>
#include <QFile>
#include <QTextStream>
#include <QMessageBox>
#include <QKeyEvent>
#include <QSettings>
#include <QLineEdit>
#include <QFileDialog>
#include <QProcess>
#include <string>
#include <QMessageBox>
#include <QDebug>

#include "astviewmodel.h"
#include "../parser/ast_to_json.hpp"
#include "selection_list_model.h"

using cyclone::parser::AstToJson;
using cyclone::parser::ParseOption;

static auto getStyle(const QString &style, int scaledSize = 96)
{
    qDebug() << "Scaled size is " << scaledSize;
    QFile qss(style);
    if (!qss.open(QFile::ReadOnly))
    {
        qWarning() << QStringLiteral("加载样式文件失败:") << style;
    }
    QString strStyle = qss.readAll();
    qss.close();
    return strStyle;
}

class AcornParser
{
    auto runJs(const QStringList &args)
    {
        QProcess subProcess;
        std::string file_path = __FILE__;
        auto dir_path = file_path.substr(0, file_path.rfind("\\"));
        subProcess.setWorkingDirectory(QString::fromStdString(dir_path));
        subProcess.start("node", args, QIODevice::ReadOnly);
        subProcess.waitForStarted();
        subProcess.waitForFinished();
        return subProcess.readAll().toStdString();
    }

public:
    auto parseLoose(const QString &jsCode)
    {
        return runJs(QStringList{"acorn_parse_loose.js", jsCode});
    }
    auto parse(const QString &jsCode)
    {
        return runJs(QStringList{"acorn_parse.js", jsCode});
    }

private:
};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow), setting_(new QSettings("generatorSetting.ini", QSettings::IniFormat)),
      parseLoose_(false)
{
    ui->setupUi(this);
    antlrParserModel_ = new AstViewModel(ui->antlrParserView);
    ui->antlrParserView->setModel(antlrParserModel_);
    ui->antlrParserView->header()->setSectionResizeMode(QHeaderView::Stretch);
    antlrParser_.reset(new cyclone::parser::AstToJson);

    acornParserModel_ = new AstViewModel(ui->acornView);
    ui->acornView->setModel(acornParserModel_);
    ui->acornView->header()->setSectionResizeMode(QHeaderView::Stretch);
    {
        static const auto availalbeMode = QVector<Selection>{
            {"自动", ViewerMode::Auto},
            {"正式", ViewerMode::Formal},
            {"宽松", ViewerMode::Loose},
        };
        modelSelectedMode_ = new SelectionListModel(availalbeMode, ui->viewParseMode);
        ui->viewParseMode->setModel(modelSelectedMode_);
    }
    {
        static auto availalbeRules = QVector<Selection>{{"program", "program"}};

        for (const auto &rule : antlrParser_->getSpecializedRuleNames())
            availalbeRules.append(Selection{QString::fromStdString(rule), QString::fromStdString(rule)});

        modelSelectedRule_ = new SelectionListModel(availalbeRules, ui->viewParseMode);
        ui->viewRuleApplied->setModel(modelSelectedRule_);
    }

    connect(
        ui->editProgram, &QTextEdit::textChanged, this, [&]()
        {
        const auto& jsCode = ui->editProgram->toPlainText();
        mode_ = static_cast<ViewerMode>(modelSelectedMode_->data(ui->viewParseMode->currentIndex() ,Qt::EditRole).toInt());
        selectedRule_ = modelSelectedRule_->data(ui->viewRuleApplied->currentIndex()  ,Qt::EditRole).toString().toStdString();
        qDebug() << "Cureent mode is " << mode_;
         qDebug() << "Cureent rule is " << QString::fromStdString( selectedRule_ );
        auto callAntlrParser = [&]()
        {
            Json res;
            ParseOption option {false, false, selectedRule_, jsCode.toStdString() };
            switch (mode_) {
            case ViewerMode::Auto:
                res = antlrParser_->parse(option);
                if(! res["message"].is_null())
                    res =  antlrParser_->parseLoose(option);
                break;
            case ViewerMode::Formal:
                res = antlrParser_->parse(option);
                break;
            case ViewerMode::Loose:
                res = antlrParser_->parseLoose(option);
                break;

            }
            ui->labelErrorMsg->setStyleSheet(QString("color: #F21212;"));
            if(!res.empty() &&  res.end() != res.find("message"))
            ui->labelErrorMsg->setText(res["message"].is_null() ? "" : QString::fromStdString(res["message"]));
            else
            ui->labelErrorMsg->clear();
            std::string ff = res.dump();
                        qDebug() <<QString::fromStdString(ff);
            antlrParserModel_->loadJson(QByteArray::fromStdString(ff));
            ui->antlrParserView->expandAll();
        };
        auto callAcornParser = [&]()
        {
            AcornParser parser;
            std::string res;
            switch (mode_) {
            case ViewerMode::Auto:
                res = parser.parse(jsCode);
                if(res.empty())
                    res =  parser.parseLoose(jsCode);
                break;
            case ViewerMode::Formal:
                res = parser.parse(jsCode);
                break;
            case ViewerMode::Loose:
                res = parser.parseLoose(jsCode);
                break;

            }
            acornParserModel_->loadJson(QByteArray::fromStdString(res));
            ui->acornView->expandAll();
        };
        callAcornParser();
        callAntlrParser(); },
        Qt::QueuedConnection);
    setStyleSheet(getStyle(":/qdarkstyle/dark/style.qss"));
    ui->editProgram->installEventFilter(this);
    showMaximized();
    setWindowTitle("AstViewer");
}

MainWindow::~MainWindow()
{
    delete ui;
}

bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
    /*     if (watched == ui->editProgram && event->type() == QEvent::KeyPress)
        {
            auto pressEvt = reinterpret_cast<QKeyEvent *>(event);
            if (pressEvt->key() == Qt::Key::Key_F2 || pressEvt->key() == Qt::Key::Key_Return)
            {
                ui->btnOk->click();
            }
        } */
    return QWidget::eventFilter(watched, event);
}
